﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Configuration.Provider;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Security.Permissions;
using System.Web;
using System.Globalization;


namespace Cosoware.Web.Navigation
{
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    public partial class CalendarSiteMapProvider : SiteMapProvider
    {
        private static string _applicationPath;

        /// <summary>
        /// Gets the current URL from <see cref="System.Web.HttpContext"/>.
        /// </summary>
        /// <returns></returns>
        private static string GetCurrentUrl()
        {
            HttpContext currentContext = HttpContext.Current;
            if (currentContext == null)
                throw new Exception("HttpContext.Current is Invalid");
            return currentContext.Request.RawUrl;
        }

        private static string ApplicationPath
        {
            get
            {
                if (String.IsNullOrEmpty(_applicationPath))
                {
                    HttpContext currentContext = HttpContext.Current;
                    if (currentContext == null)
                        throw new Exception("HttpContext.Current is Invalid");
                    _applicationPath = currentContext.Request.ApplicationPath;
                }
                return _applicationPath;
            }
        }

        /// <summary>
        /// The parent site map provider.
        /// </summary>
        private SiteMapProvider _parentProvider = null;

        /// <summary>
        /// The root site map node.
        /// </summary>
        private SiteMapNode _rootNode = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="CalendarSiteMapProvider"/> class.
        /// </summary>
        public CalendarSiteMapProvider()
        {
        }

        /// <summary>
        /// Gets the title.
        /// </summary>
        /// <value>The title.</value>
        public string Title
        {
            get { return _title; }
        }

        /// <summary>
        /// Gets the <see cref="T:System.Web.SiteMapNode"/> object that represents the currently requested page.
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref="T:System.Web.SiteMapNode"/> that represents the currently requested page; otherwise, null, if the <see cref="T:System.Web.SiteMapNode"/> is not found or cannot be returned for the current user.</returns>
        public override SiteMapNode CurrentNode
        {
            get
            {
                string currentUrl = GetCurrentUrl();
                // Find the SiteMapNode that represents the current page.
                SiteMapNode currentNode = FindSiteMapNode(currentUrl);
                return currentNode;
            }
        }

        /// <summary>
        /// Gets the root <see cref="T:System.Web.SiteMapNode"/> object of the site map data that the current provider represents.
        /// </summary>
        /// <value></value>
        /// <returns>The root <see cref="T:System.Web.SiteMapNode"/> of the current site map data provider. The default implementation performs security trimming on the returned node.</returns>
        public override SiteMapNode RootNode
        {
            get { return _rootNode; }
        }

        /// <summary>
        /// Gets or sets the parent <see cref="T:System.Web.SiteMapProvider"/> object of the current provider.
        /// </summary>
        /// <value></value>
        /// <returns>The parent provider of the current <see cref="T:System.Web.SiteMapProvider"/>.</returns>
        public override SiteMapProvider ParentProvider
        {
            get { return _parentProvider; }
            set { _parentProvider = value; }
        }

        /// <summary>
        /// Gets the root <see cref="T:System.Web.SiteMapProvider"/> object in the current provider hierarchy.
        /// </summary>
        /// <value></value>
        /// <returns>An <see cref="T:System.Web.SiteMapProvider"/> that is the top-level site map provider in the provider hierarchy that the current provider belongs to.</returns>
        /// <exception cref="T:System.Configuration.Provider.ProviderException">There is a circular reference to the current site map provider. </exception>
        public override SiteMapProvider RootProvider
        {
            get { return ParentProvider != null ? ParentProvider.RootProvider : this; }
        }

        /// <summary>
        /// When overridden in a derived class, retrieves a <see cref="T:System.Web.SiteMapNode"/> object that represents the page at the specified URL.
        /// </summary>
        /// <param name="rawUrl">A URL that identifies the page for which to retrieve a <see cref="T:System.Web.SiteMapNode"/>.</param>
        /// <returns>
        /// A <see cref="T:System.Web.SiteMapNode"/> that represents the page identified by <paramref name="rawURL"/>; otherwise, null, if no corresponding <see cref="T:System.Web.SiteMapNode"/> is found or if security trimming is enabled and the <see cref="T:System.Web.SiteMapNode"/> cannot be returned for the current user.
        /// </returns>
        public override SiteMapNode FindSiteMapNode(string rawUrl)
        {
            Regex dateRegex = new Regex(@"d=(?'date'[0-9]{4}([0-9][0-9])?([0-9][0-9])?)");
            Match match = dateRegex.Match(rawUrl);
            lock (this)
            {
                if (match.Groups["date"].Success)
                {
                    String key = GetUrl(match.Groups["date"].Captures[0].Value);
                    if (_nodes.ContainsKey(key))
                        return _nodes[key];
                }
                if (_nodes.ContainsKey(rawUrl))
                    return _rootNode;
            }
            return null;
        }

        /// <summary>
        /// When overridden in a derived class, retrieves the child nodes of a specific <see cref="T:System.Web.SiteMapNode"/>.
        /// </summary>
        /// <param name="node">The <see cref="T:System.Web.SiteMapNode"/> for which to retrieve all child nodes.</param>
        /// <returns>
        /// A read-only <see cref="T:System.Web.SiteMapNodeCollection"/> that contains the immediate child nodes of the specified <see cref="T:System.Web.SiteMapNode"/>; otherwise, null or an empty collection, if no child nodes exist.
        /// </returns>
        public override SiteMapNodeCollection GetChildNodes(SiteMapNode node)
        {
            SiteMapNodeCollection collection = new SiteMapNodeCollection();
            lock (this)
            {
                if (_childNodes.ContainsKey(node))
                {
                    List<SiteMapNode> list = _childNodes[node];
                    collection.AddRange(list.ToArray());
                }
            }
            return collection;
        }

        /// <summary>
        /// When overridden in a derived class, retrieves the parent node of a specific <see cref="T:System.Web.SiteMapNode"/> object.
        /// </summary>
        /// <param name="node">The <see cref="T:System.Web.SiteMapNode"/> for which to retrieve the parent node.</param>
        /// <returns>
        /// A <see cref="T:System.Web.SiteMapNode"/> that represents the parent of <paramref name="node"/>; otherwise, null, if the <see cref="T:System.Web.SiteMapNode"/> has no parent or security trimming is enabled and the parent node is not accessible to the current user.<see cref="M:System.Web.SiteMapProvider.GetParentNode(System.Web.SiteMapNode)"/> might also return null if the parent node belongs to a different provider. In this case, use the <see cref="P:System.Web.SiteMapNode.ParentNode"/> property of <paramref name="node"/> instead.
        /// </returns>
        public override SiteMapNode GetParentNode(SiteMapNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }
            lock (this)
            {
                if (_parentNodes.ContainsKey(node.Key))
                    return _parentNodes[node.Key];
                if (ParentProvider != null)
                    return ParentProvider.GetParentNode(node);
            }
            return null;
        }

        /// <summary>
        /// When overridden in a derived class, retrieves the root node of all the nodes that are currently managed by the current provider.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Web.SiteMapNode"/> that represents the root node of the set of nodes that the current provider manages.
        /// </returns>
        protected override SiteMapNode GetRootNodeCore()
        {
            return _rootNode;
        }
    }
}
